package com.ctshk.rpc.air.service.impl.es;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ctshk.common.enums.NumberConstant;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.rpc.air.entity.*;
import com.ctshk.rpc.air.entity.es.*;
import com.ctshk.rpc.air.mapper.*;
import com.ctshk.rpc.air.mapper.es.AirProductEsMapper;
import com.ctshk.rpc.air.req.AirBookingListReq;
import com.ctshk.rpc.air.req.app.AirTicketsListReq;
import com.google.common.collect.Lists;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @BelongsProject: ctshk-cloud
 * @BelongsPackage: com.ctshk.rpc.air.service.impl.es
 * @Author: hef
 * @CreateTime: 2021-04-16 16:53
 * @Description: 描述
 */
@Service
public class AirProductEsService {
    @Autowired
    private AirProductEsMapper airProductEsMapper;
    @Autowired
    private AirProductCostMapper airProductCostMapper;
    @Autowired
    private AirProductSaleStrategyVaildDateMapper airProductSaleStrategyVaildDateMapper;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Resource
    private AirProductChannelOnlineSelfPlatformMapper airProductChannelOnlineSelfPlatformMapper;
    @Resource
    private AirProductCostDateMapper airProductCostDateMapper;
    @Resource
    private AirProductCostTouristMapper airProductCostTouristMapper;
    @Resource
    private AirProductCostTaxationMapper airProductCostTaxationMapper;
    @Resource
    private AirProductMapper airProductMapper;
    @Resource
    private AirFlightMapper airFlightMapper;
    @Resource
    private AirProductReservationSettingsMapper airProductReservationSettingsMapper;

    /**
     * 保存
     *
     * @param
     */
    public void save() {
        //获取航班信息
        List<AirProduct> airProducts = airProductMapper.selectList(Wrappers.query());
        List<AirProductEs> saveList = Lists.newArrayList();
        airProducts.forEach(item -> {
            AirProductEs copy = new AirProductEs();
            BeanUtils.copyProperties(item, copy);
            copy.setProductId(item.getId());
            AirProductReservationSettings airProductReservationSettings = airProductReservationSettingsMapper.selectOne(Wrappers.<AirProductReservationSettings>lambdaQuery()
                    .eq(AirProductReservationSettings::getAirProductId, item.getId()));
            copy.setAirProductPriceSettingsDTO(EntityUtil.copy(airProductReservationSettings,
                    AirProductPriceSettingsEs.class));
            //获取航班信息
            AirFlight airFlight = airFlightMapper.selectById(item.getRouteId());
            if (airFlight == null) return;
            BeanUtils.copyProperties(airFlight, copy);
            copy.setFlightId(airFlight.getId());
            copy.setDepAirportId(airFlight.getDepAirportId());
            //获取成本信息
            List<AirProductCost> airProductCosts = airProductCostMapper.selectList(Wrappers.
                    <AirProductCost>lambdaQuery().eq(AirProductCost::getAirProductId, item.getId()));
            if (CollectionUtils.isEmpty(airProductCosts)) return;
            List<AirProductCostEs> costList = Lists.newArrayList();
            airProductCosts.stream().forEach(cost -> {
                List<AirProductCostDate> airProductCostDates = airProductCostDateMapper.selectList(
                        Wrappers.<AirProductCostDate>lambdaQuery()
                                .eq(AirProductCostDate::getCostId, cost.getId())
                                .ge(AirProductCostDate::getDateEnd, LocalDate.now())
                );
                if (CollectionUtils.isEmpty(airProductCostDates)) return;
                airProductCostDates.stream().forEach(costDate -> {
                    //获取旅客成本
                    List<AirProductCostTourist> airProductCostTourists = airProductCostTouristMapper.selectList(
                            Wrappers.<AirProductCostTourist>lambdaQuery()
                                    .eq(AirProductCostTourist::getCostId, costDate.getCostId())
                    );
                    if (CollectionUtils.isNotEmpty(airProductCostTourists)) {
                        List<AirBookingListTouristEs> airBookingListTouristEs = Lists.newArrayList();
                        airProductCostTourists.forEach(costTourist -> {
                            AirBookingListTouristEs touristEs = EntityUtil.copy(costTourist, AirBookingListTouristEs.class);
                            List<AirProductCostTaxation> airProductCostTaxations = airProductCostTaxationMapper.selectList(
                                    Wrappers.<AirProductCostTaxation>lambdaQuery()
                                            .eq(AirProductCostTaxation::getTouristId, costTourist.getId())
                            );
                            touristEs.setAirProductCostTaxationDTOList(EntityUtil.copyList(airProductCostTaxations, AirProductCostTaxationEs.class));
                            airBookingListTouristEs.add(touristEs);
                        });
                        costList.add(new AirProductCostEs(
                                costDate.getDateBegin(), costDate.getDateEnd(),
                                cost.getCurrencyId(), cost.getCurrencyName(),
                                airBookingListTouristEs
                        ));
                    }
                });
            });
            copy.setProductCostList(costList);
            //获取有效期内的线上加幅
            List<AirProductSaleStrategyVaildDate> airProductSaleStrategyVaildDates =
                    airProductSaleStrategyVaildDateMapper.selectList(
                            Wrappers.<AirProductSaleStrategyVaildDate>lambdaQuery()
                                    .eq(AirProductSaleStrategyVaildDate::getProductId, copy.getProductId()));
            if (CollectionUtils.isEmpty(airProductSaleStrategyVaildDates)) return;
            List<AirProductSaleStrategyEs> saleStrategy = Lists.newArrayList();
            airProductSaleStrategyVaildDates.stream().forEach(strategyDate -> {
                //是否有效时间
                if (strategyDate.getTimeBegin().isBefore(LocalDate.now()) &&
                        strategyDate.getTimeEnd().isAfter(LocalDate.now())) {
                    //查找线上加幅策略
                    List<AirProductChannelOnlineSelfPlatform> airProductChannelOnlineSelfPlatforms =
                            airProductChannelOnlineSelfPlatformMapper.selectList(Wrappers.
                                    <AirProductChannelOnlineSelfPlatform>lambdaQuery()
                                    .eq(AirProductChannelOnlineSelfPlatform::getStrategyId, strategyDate.getStrategyId()));
                    if (CollectionUtils.isNotEmpty(airProductChannelOnlineSelfPlatforms)) {
                        saleStrategy.add(new AirProductSaleStrategyEs(
                                strategyDate.getTimeBegin(),
                                strategyDate.getTimeEnd(),
                                EntityUtil.copyList(airProductChannelOnlineSelfPlatforms, AirProductChannelOnlineSelfPlatformEs.class)
                        ));
                    }
                }
            });
            copy.setSaleStrategy(saleStrategy);
            //默认都是直达
            copy.setOnWay(1);
            if (CollectionUtils.isEmpty(copy.getSaleStrategy()) || CollectionUtils.isEmpty(copy.getProductCostList())) return;
            saveList.add(copy);
        });
        if (CollectionUtils.isNotEmpty(saveList)) {
            airProductEsMapper.saveAll(saveList);
        }
    }

    /**
     * App获取列表
     *
     * @param req
     * @return
     */
    public Page<AirProductEs> searchListPage(AirTicketsListReq req) {
        BoolQueryBuilder boolQueryBuilder1 = buildQuery(req);
        Page<AirProductEs> page = airProductEsMapper.search(boolQueryBuilder1,
                PageRequest.of(req.getPageNo() - 1, req.getPageSize()));
        return page;
    }

    /**
     * PC获取数据
     *
     * @param req
     * @return
     */
    public List<AirProductEs> searchList(AirTicketsListReq req) {
        BoolQueryBuilder query = buildQuery(req);
        Iterable<AirProductEs> search = airProductEsMapper.search(query);
        return toList(search, req.getChannelId());
    }

    /**
     * PC获取数据
     *
     * @param req
     * @return
     */
    public List<AirProductEs> searchListAttr(AirTicketsListReq req) {
        BoolQueryBuilder query = buildQuery(req);
        Iterable<AirProductEs> search = airProductEsMapper.search(query);
        return toListAttr(search, req.getChannelId(), req.getCurrentTimes());
    }

    /**
     * 转List 并且计算最低价
     *
     * @param iterable
     * @param channelId
     * @return
     */
    public List<AirProductEs> toListAttr(Iterable<AirProductEs> iterable, Long channelId, LocalDate currentTimes) {
        List<AirProductEs> productList = Lists.newArrayList();
        iterable.forEach(item -> {
            AirProductEs airProductEs = calculateTheMinimumPcAttr(channelId, item, currentTimes);
            if (Objects.nonNull(airProductEs)) productList.add(airProductEs);
        });
        return productList;
    }

    /**
     * 构建查询条件
     *
     * @param req
     * @return
     */
    private BoolQueryBuilder buildQuery(AirTicketsListReq req) {
        //组织查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("saleStrategy.channelOnlineSelfPlatform.channelId", req.getChannelId()));
        if (CollectionUtils.isNotEmpty(req.getCabinClass())) {
            boolQueryBuilder.must(QueryBuilders.termsQuery("cabinClass", req.getCabinClass()));
        }
        if (CollectionUtils.isNotEmpty(req.getCompanyIds())) {
            boolQueryBuilder.must(QueryBuilders.termsQuery("companyIds", req.getCompanyIds()));
        }
        if (CollectionUtils.isNotEmpty(req.getTouristTypeIds())) {
            req.getTouristTypeIds().stream().map(AirBookingListReq.TouristTypeValue::getTouristType).collect(Collectors.toList())
                    .stream().forEach(item -> {
                boolQueryBuilder.must(
                        QueryBuilders.termQuery("productCostList.airBookingListTourist.touristTypeId", item)
                );
            });
        }
        if (CollectionUtils.isNotEmpty(req.getAirBookingListDateReqList())) {
            List list = Lists.newArrayList();
            req.getAirBookingListDateReqList().forEach(item -> {
                list.add(QueryBuilders
                        .rangeQuery("depTime")
                        .gte(item.getStartTime().format(DateTimeFormatter.ofPattern("HH:mm")))
                        .lte(item.getEndTime().format(DateTimeFormatter.ofPattern("HH:mm"))));
            });
            boolQueryBuilder.should().addAll(list);
        }
        if (Objects.nonNull(req.getDepDate())) {
            boolQueryBuilder.must(
                    QueryBuilders.rangeQuery("productCostList.validStartDate").lte(req.getDepDate())
            );
            boolQueryBuilder.must(
                    QueryBuilders.rangeQuery("productCostList.validEndDate").gte(req.getDepDate())
            );
            boolQueryBuilder.must(
                    QueryBuilders.rangeQuery("saleStrategy.validStartDate").lte(req.getDepDate())
            );
            boolQueryBuilder.must(
                    QueryBuilders.rangeQuery("saleStrategy.validEndDate").gte(req.getDepDate())
            );
        }
        if (Objects.nonNull(req.getDepCityId())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("depCityId", req.getDepCityId()));
        }
        if (Objects.nonNull(req.getArrCityId())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("arrCityId", req.getArrCityId()));
        }
        return boolQueryBuilder;
    }


    /**
     * 获取推荐列表
     *
     * @param channelId
     * @return
     */
    public List<AirProductEs> getRecommendedTicket(Long channelId) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.matchQuery("recommendStatus", 1));
        if (channelId != null) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("saleStrategy.channelOnlineSelfPlatform.channelId", channelId));
        }
        Iterable<AirProductEs> search = airProductEsMapper.search(boolQueryBuilder);
        return toList(search, channelId);
    }


    /**
     * 转List 并且计算最低价
     *
     * @param iterable
     * @param channelId
     * @return
     */
    public List<AirProductEs> toList(Iterable<AirProductEs> iterable, Long channelId) {
        List<AirProductEs> productList = Lists.newArrayList();
        iterable.forEach(item -> {
            AirProductEs airProductEs = calculateTheMinimumPrice(channelId, item);
            if (Objects.nonNull(airProductEs)) productList.add(airProductEs);
        });
        return productList;
    }

    /**
     * 计算最低价
     *
     * @param channelId
     * @param list
     * @return
     */
    public List<AirProductEs> calculateTheMinimumPrice(Long channelId,LocalDate currentTimes, List<AirProductEs> list) {
        List<AirProductEs> rtnList = Lists.newArrayList();
        list.stream().forEach(item -> {
            AirProductEs airProductEs = calculateTheMinimumPriceAttr(channelId,currentTimes, item);
            if (Objects.nonNull(airProductEs)) rtnList.add(airProductEs);
        });
        return rtnList;
    }

    /**
     * 计算最低价
     *
     * @param channelId
     * @param item
     * @return
     */
    private AirProductEs calculateTheMinimumPriceAttr(Long channelId,LocalDate currentTimes, AirProductEs item) {
        if (Objects.isNull(item)) return null;
        LocalDate currentTime = currentTimes;
        //加幅策略
        Optional<AirProductSaleStrategyEs> saleStrategy = item.getSaleStrategy().stream().filter(strategy ->
                strategy.getValidStartDate().isBefore(currentTime) && strategy.getValidEndDate().isAfter(currentTime)
        ).findFirst();
        if (!saleStrategy.isPresent()) return null;
        Optional<AirProductChannelOnlineSelfPlatformEs> st =
                saleStrategy.get().getChannelOnlineSelfPlatform().stream().filter(o -> o.getChannelId().equals(channelId)).findFirst();
        if (!st.isPresent()) return null;
        //成本
        Optional<AirProductCostEs> productCost = item.getProductCostList().stream().filter(cost ->
                cost.getValidStartDate().isBefore(currentTime) && cost.getValidEndDate().isAfter(currentTime)
        ).findFirst();
        if (!productCost.isPresent()) return null;
        Optional<AirBookingListTouristEs> min = productCost.get().getAirBookingListTouristDTOList()
                .stream().min(Comparator.comparing(AirBookingListTouristEs::getCostPrice));
        //获取最低价
        BigDecimal minAmt = BigDecimal.ZERO;
        AirProductChannelOnlineSelfPlatformEs s = st.get();
        //加数值
        if (s.getAdjustType().equals(NumberConstant.ONE.getValue())) {
            if (s.getAmount() == null) return null;
            minAmt = min.get().getCostPrice().add(s.getAmount());
        }
        //加百分比
        else {
            if (s.getPercent() == null) return null;
            minAmt = min.get().getCostPrice().add(min.get().getCostPrice().multiply(
                    BigDecimal.valueOf(s.getPercent()).divide(BigDecimal.valueOf(100))
                            .setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        return item.setLowPrice(minAmt);
    }

    /**
     * 计算最低价
     *
     * @param channelId
     * @param item
     * @return
     */
    private AirProductEs calculateTheMinimumPrice(Long channelId, AirProductEs item) {
        if (Objects.isNull(item)) return null;
        LocalDate currentTime = LocalDate.now();
        //加幅策略
        Optional<AirProductSaleStrategyEs> saleStrategy = item.getSaleStrategy().stream().filter(strategy ->
                strategy.getValidStartDate().isBefore(currentTime) && strategy.getValidEndDate().isAfter(currentTime)
        ).findFirst();
        if (!saleStrategy.isPresent()) return null;
        Optional<AirProductChannelOnlineSelfPlatformEs> st =
                saleStrategy.get().getChannelOnlineSelfPlatform().stream().filter(o -> o.getChannelId().equals(channelId)).findFirst();
        if (!st.isPresent()) return null;
        //成本
        Optional<AirProductCostEs> productCost = item.getProductCostList().stream().filter(cost ->
                cost.getValidStartDate().isBefore(currentTime) && cost.getValidEndDate().isAfter(currentTime)
        ).findFirst();
        if (!productCost.isPresent()) return null;
        Optional<AirBookingListTouristEs> min = productCost.get().getAirBookingListTouristDTOList()
                .stream().min(Comparator.comparing(AirBookingListTouristEs::getCostPrice));
        //获取最低价
        BigDecimal minAmt = BigDecimal.ZERO;
        AirProductChannelOnlineSelfPlatformEs s = st.get();
        //加数值
        if (s.getAdjustType().equals(NumberConstant.ONE.getValue())) {
            if (s.getAmount() == null) return null;
            minAmt = min.get().getCostPrice().add(s.getAmount());
        }
        //加百分比
        else {
            if (s.getPercent() == null) return null;
            minAmt = min.get().getCostPrice().add(min.get().getCostPrice().multiply(
                    BigDecimal.valueOf(s.getPercent()).divide(BigDecimal.valueOf(100))
                            .setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        return item.setLowPrice(minAmt);
    }

    /**
     * 计算最低价
     *
     * @param channelId
     * @param item
     * @return
     */
    private AirProductEs calculateTheMinimumPcAttr(Long channelId, AirProductEs item, LocalDate currentTimes) {
        if (Objects.isNull(item)) return null;
        //LocalDate currentTime = LocalDate.now();
        LocalDate currentTime = currentTimes;
        //加幅策略
        Optional<AirProductSaleStrategyEs> saleStrategy = item.getSaleStrategy().stream().filter(strategy ->
                strategy.getValidStartDate().isBefore(currentTime) && strategy.getValidEndDate().isAfter(currentTime)
        ).findFirst();
        if (!saleStrategy.isPresent()) return null;
        Optional<AirProductChannelOnlineSelfPlatformEs> st =
                saleStrategy.get().getChannelOnlineSelfPlatform().stream().filter(o -> o.getChannelId().equals(channelId)).findFirst();
        if (!st.isPresent()) return null;
        //成本
        Optional<AirProductCostEs> productCost = item.getProductCostList().stream().filter(cost ->
                cost.getValidStartDate().isBefore(currentTime) && cost.getValidEndDate().isAfter(currentTime)
        ).findFirst();
        if (!productCost.isPresent()) return null;
        Optional<AirBookingListTouristEs> min = productCost.get().getAirBookingListTouristDTOList()
                .stream().min(Comparator.comparing(AirBookingListTouristEs::getCostPrice));
        //获取最低价
        BigDecimal minAmt = BigDecimal.ZERO;
        AirProductChannelOnlineSelfPlatformEs s = st.get();
        //加数值
        if (s.getAdjustType().equals(NumberConstant.ONE.getValue())) {
            if (s.getAmount() == null) return null;
            minAmt = min.get().getCostPrice().add(s.getAmount());
        }
        //加百分比
        else {
            if (s.getPercent() == null) return null;
            minAmt = min.get().getCostPrice().add(min.get().getCostPrice().multiply(
                    BigDecimal.valueOf(s.getPercent()).divide(BigDecimal.valueOf(100))
                            .setScale(2, BigDecimal.ROUND_HALF_UP)));
        }
        return item.setLowPrice(minAmt);
    }
}
